package com.strato.annotation.base.v1_0_0.registry.impl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

import org.osgi.framework.Bundle;

import com.strato.annotation.base.v1_0_0.activator.Activator;
import com.strato.annotation.base.v1_0_0.handler.AnnotationHandler;
import com.strato.annotation.base.v1_0_0.registry.AnnotationRegistry;
import com.strato.annotation.base.v1_0_0.registry.BundleDescriptor;
import com.strato.annotation.base.v1_0_0.registry.ClassDescriptor;
import com.strato.annotation.base.v1_0_0.registry.FieldDescriptor;
import com.strato.annotation.base.v1_0_0.registry.MethodDescriptor;
import com.strato.base.bean.v1_0_0.BeanUtil;
import com.strato.base.osgi.v1_0_0.BundleUtil;

public class AnnotationRegistryImpl implements AnnotationRegistry {

	private List<BundleDescriptor> bundleDescriptors = new ArrayList<BundleDescriptor>();

	@Override
	public List<BundleDescriptor> getBundleDescriptors() {
		return bundleDescriptors;
	}

	public void setBundleDescriptors(List<BundleDescriptor> bundleDescriptors) {
		this.bundleDescriptors = bundleDescriptors;
	}

	@Override
	public BundleDescriptor find(BundleDescriptor condition) {
		for (BundleDescriptor bd : bundleDescriptors) {
			if (bd.bequals(condition)) {
				return bd;
			}
		}
		return null;
	}

	private static AnnotationRegistryImpl instance=new AnnotationRegistryImpl();
	
	public static AnnotationRegistryImpl getInstance() {
		return instance;
	}

	@Override
	public BundleDescriptor findByClassName(String className) {
		for (BundleDescriptor bd : bundleDescriptors) {
			ClassDescriptor cd = bd.getClassDescriptor(className);
			if(cd!=null){
				return bd;
			}
		}
		return null;
	}

	@Override
	public void applyHandlers(BundleDescriptor bundleDescriptor,
			List<AnnotationHandler> handlers) {
		try{
			Bundle bundle = BundleUtil.getBundle(bundleDescriptor.getName(), Activator.getContext());
			for(AnnotationHandler handler:handlers){
				for(ClassDescriptor cd:bundleDescriptor.getClassDescriptors()){
					Class<?> clazz=BundleUtil.loadClass(bundle,cd.getClassName());
					{
						List<Annotation> annotations = cd.getAnnotations();
						for(Annotation annotation:annotations){
							handler.handleClass(bundle,clazz,annotation);
						}
					}
					for(FieldDescriptor fd:cd.getFieldDescriptors()){
						List<Annotation> annotations = fd.getAnnotations();
						Field field = BeanUtil.getField(clazz, fd.getFieldName());
						for(Annotation annotation:annotations){
							handler.handleField(bundle,field,clazz,annotation);
						}
					}
					for(MethodDescriptor md:cd.getMethodDescriptors()){
						Class<?>[] parameterTypes=new Class<?>[md.getArgumentDescriptors().size()];
						for(int i=0,len=md.getArgumentDescriptors().size();i<len;i++){
							parameterTypes[i]=BundleUtil.loadClass(bundle,md.getArgumentDescriptors().get(i).getTypeName());
						}
						Method method=BeanUtil.getMethod(clazz, md.getMethodName(), parameterTypes);
						for(Annotation annotation:md.getAnnotations()){
							handler.handleMethod(bundle,method,clazz,annotation);
						}
						Parameter[] params = method.getParameters();
						for(Parameter p:params){
							for(Annotation annotation:p.getAnnotations()){
								handler.handleMethodParameter(bundle,method,p,clazz,annotation);
							}
						}
					}
				}
			}
		}catch(ClassNotFoundException e){
			throw new RuntimeException(e);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		}
	}
}
